{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第 3 章：TensorFlow"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.10.0\n"
     ]
    }
   ],
   "source": [
    "# 导入 tensorflow\n",
    "import tensorflow as tf\n",
    "\n",
    "# 查看 tensorflow 版本\n",
    "print(tf.__version__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 张量 Tensor"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建 Tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 0 阶 Tensor\n",
    "c0 = tf.constant(2, name='c0')\n",
    "# 1 阶 Tensor\n",
    "c1 = tf.constant([1, 2, 3], name='c1')\n",
    "# 2 阶 Tensor\n",
    "c2 = tf.constant([[1, 2], [3, 4]], name='c2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tensor(\"c0:0\", shape=(), dtype=int32)\n",
      "Tensor(\"c1:0\", shape=(3,), dtype=int32)\n",
      "Tensor(\"c2:0\", shape=(2, 2), dtype=int32)\n"
     ]
    }
   ],
   "source": [
    "print(c0)\n",
    "print(c1)\n",
    "print(c2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tensor数学运算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tensor(\"add:0\", shape=(2, 2), dtype=int32)\n",
      "Tensor(\"sub:0\", shape=(2, 2), dtype=int32)\n",
      "Tensor(\"multiply:0\", shape=(2, 2), dtype=int32)\n",
      "Tensor(\"matmul:0\", shape=(2, 2), dtype=int32)\n"
     ]
    }
   ],
   "source": [
    "a = tf.constant([[1, 2], [3, 4]], name='a')\n",
    "b = tf.constant([[5, 6], [7, 8]], name='b')\n",
    "# 加法\n",
    "out = tf.add(a, b, name='add')\n",
    "print(out)\n",
    "# 减法\n",
    "out = tf.subtract(a, b, name='sub')\n",
    "print(out)\n",
    "# 对应元素相乘\n",
    "out = tf.multiply(a, b, name='multiply')\n",
    "print(out)\n",
    "# 矩阵相乘\n",
    "out = tf.matmul(a, b, name='matmul')\n",
    "print(out)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据流图（Data Flow Graph）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](./datasets/ch03/3-3.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "c = tf.constant(2, name='const')\n",
    "\n",
    "a = tf.Variable(3, name='a')\n",
    "b = tf.Variable(4, name='b')\n",
    "\n",
    "f = a*a + a*b +c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 会话（Session）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 会话机制 1 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "23\n"
     ]
    }
   ],
   "source": [
    "sess = tf.Session()\n",
    "sess.run(a.initializer)\n",
    "sess.run(b.initializer)\n",
    "result = sess.run(f)\n",
    "print(result)\n",
    "\n",
    "sess.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 会话机制 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "23\n"
     ]
    }
   ],
   "source": [
    "with tf.Session() as sess:\n",
    "    a.initializer.run()\n",
    "    b.initializer.run()\n",
    "    result = f.eval()\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 会话机制 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "init = tf.global_variables_initializer()    # 定义全局初始化节点\n",
    "\n",
    "with tf.Session() as sess:\n",
    "    init.run()    # 初始化所有变量\n",
    "    result = f.eval()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 占位符 tf.placeholder()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Situation 1:\n",
      " [12.]\n",
      "Situation 2:\n",
      " [[2. 4.]\n",
      " [6. 8.]]\n"
     ]
    }
   ],
   "source": [
    "# 在 Tensorflow 中需要定义 placeholder 的 type，一般为 float32\n",
    "a = tf.placeholder(tf.float32, name='a')\n",
    "b = tf.placeholder(tf.float32, name='b')\n",
    "f = tf.multiply(a, b)\n",
    "\n",
    "with tf.Session() as sess:\n",
    "    print('Situation 1:\\n', sess.run(f, feed_dict={a: [3.], b: [4.]}))\n",
    "    print('Situation 2:\\n',sess.run(f, feed_dict={a:[[1.,2.],[3.,4.]], b: [2.]}))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TensorFlow 线性回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train = np.linspace(-1, 1, 50)\n",
    "y_train = 3*x_train + 10 + 0.5 * np.random.randn(x_train.shape[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "显示数据分布"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams['font.sans-serif']=['SimHei']\n",
    "plt.rcParams['axes.unicode_minus']=False\n",
    "plt.rcParams['figure.figsize'] = (10.0, 6.0) # set default size of plots\n",
    "\n",
    "plt.scatter(x_train, y_train)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建输入节点 x 和 y，用于输入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = tf.placeholder(tf.float32, name='x')\n",
    "y = tf.placeholder(tf.float32, name='y')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建变量节点 w1 和 w0，并初始化变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "w1 = tf.Variable(tf.random_normal([1]), name='w1')\n",
    "w0 = tf.Variable(tf.zeros([1]), name='w0')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建线性模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_hat = w0 + w1 * x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建损失模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "loss = tf.reduce_mean(tf.square(y_hat - y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建一个梯度下降优化器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "optimizer = tf.train.GradientDescentOptimizer(0.01)    # 学习率设为 0.01\n",
    "train = optimizer.minimize(loss)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建会话 Session 用来计算模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "sess = tf.Session()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 初始化变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w1 = [-0.4311598] w0 = [0.]\n"
     ]
    }
   ],
   "source": [
    "init = tf.global_variables_initializer()\n",
    "sess.run(init)\n",
    "print (\"w1 =\", sess.run(w1), \"w0 =\", sess.run(w0))  # 打印初始化的w1和w0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Iteration[20/500], loss: 47.436157\n",
      "Iteration[40/500], loss: 22.252466\n",
      "Iteration[60/500], loss: 10.788024\n",
      "Iteration[80/500], loss: 5.496624\n",
      "Iteration[100/500], loss: 3.000713\n",
      "Iteration[120/500], loss: 1.784191\n",
      "Iteration[140/500], loss: 1.163201\n",
      "Iteration[160/500], loss: 0.826786\n",
      "Iteration[180/500], loss: 0.631707\n",
      "Iteration[200/500], loss: 0.510594\n",
      "Iteration[220/500], loss: 0.430753\n",
      "Iteration[240/500], loss: 0.375594\n",
      "Iteration[260/500], loss: 0.336194\n",
      "Iteration[280/500], loss: 0.307420\n",
      "Iteration[300/500], loss: 0.286107\n",
      "Iteration[320/500], loss: 0.270183\n",
      "Iteration[340/500], loss: 0.258223\n",
      "Iteration[360/500], loss: 0.249212\n",
      "Iteration[380/500], loss: 0.242410\n",
      "Iteration[400/500], loss: 0.237269\n",
      "Iteration[420/500], loss: 0.233382\n",
      "Iteration[440/500], loss: 0.230442\n",
      "Iteration[460/500], loss: 0.228216\n",
      "Iteration[480/500], loss: 0.226533\n",
      "Iteration[500/500], loss: 0.225258\n"
     ]
    }
   ],
   "source": [
    "num_iter = 500\n",
    "for i in range(num_iter):\n",
    "    sess.run(train, {x: x_train, y: y_train})\n",
    "    if (i+1) % 20 == 0:\n",
    "        print('Iteration[{}/{}], loss: {:.6f}'.format(i+1,num_iter,sess.run(loss,{x:x_train,y:y_train})))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "打印 w1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2.938043], dtype=float32)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sess.run(w1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "打印 w0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([9.940149], dtype=float32)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sess.run(w0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模型测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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7LXB8O8lIiLiK55MzcX3+ZTiEooBViVf5be2GWMWWmsTSrsuIkeg4NAjUowxAQ1Ph98fKDE8iYiIhJsOLeJKHUXydKrPLRFZiVxERESCW6/2TYiJjjrkseKm+twSsSNQIiIi4lu+3DVX+DztwhMREZGw5Y9dc55M9blFU3glyMvLw1rL3r172bVrV9Hj1lr279/vYstERESCz9F2zYWjiB6BeuONNxgxYgRxcU66PXgnXF5eHtOmTWPFihWMHz+e0aNHA/D5558zbdo03njjjUNea8CAAVxyySV89dVXVK9enW7dutGxY0c+++wzoqIOzOHu37+fTp06MX36dLp06cL69euL/q5atWp88skn/u62iIiIz3lTIDMclClAGWNOAc4EFlhrd/q2SYETFRVFjx49uP/++wH417/+xdy5c4t2yO3YsYOff/6ZRo0asXHjRmrVqsWECRN49tln+eijj2jdujU1atRg165dHHvssXz//fds2rSJDRs2sGbNGqpWrUpUVFTRmXjGGCpWrMi+ffsAyM3NZfbs2UXtURFNEREJVcG+a87XPJrCM8bUMsbMLfi6MfB/QCvgW2NMJT+2D3DmVVslzyK+z6e0Sp5FanqWT1//8ccf56KLLiI7O5tLLrmECy+8kBdeeIHZs2fzv//9j/nz59OmTRvmz5/PRRddRL169ahSpQoPPvggANu3b2fLli0MHz6c33//nRNOOIGXX36ZP/74gzZt2lCnTh3S0tKYPn067du356effqJjx46sXbuWxMREWrduTZs2bVi0aJFP+yUiIhIowb5rztdKHYEyxtQAJgBVCx46G7jTWrvCGNMMiAf8NsEZiFLu2dnZ3HbbbZx00kkApKens2PHDq699lqmTJnChAkT+O9//0vPnj3JzMzklVde4fjjj2fXrl1MnTqViy66iNWrV/PYY4+RkZHBhg0bWLJkCUOHDqVhw4a8+uqrtGzZkpYtW3L99ddz9dVX8+CDDzJu3Djeffdd3nnnHQBuuukmn/RHREQk0IJ915yveTKFlwd0Bj4EsNZONcZUNMZcBdQA/vBj+/xayn3//v1ER0djreX444/nhBNOAODYY49l505nZnLXrl1kZ2dz6qmnMmnSJGrUqFE0xbd3714qVKjAxo0befrpp5k4cSKPPvoo0dHRPPnkkyxcuJBKlSpRv379ont+++23zJ07lw4dOvD777/Trl07Nm3aBMCrr75Kly5duPfee8vVLxERETcE8645Xys1QFlrd8ARlbOrAZ2ANXBkpXVjzL3AvQB169YtVwP9uShtw4YNnHnmmTRq1IixY8eSlZVFhQoVOOWUU7jpppvIyspi8+bNvPfee7Rr146PP/6YIUOGUKtWLQBWrlzJ+vXrWbNmDf369SMzM5PFixfz888/s2rVKpKSkgC48sorAXj77beZOnUqrVu3pmvXrnz77bdMnDiRqVOnAloDJSIiEirKtIjcWpsN3G6MmQicDyw47O/HAePAOQuvPA3056K0xYsXc8MNN3D22WfTokULVq1aRZUqVTDG0LlzZ6pUqcKYMWNo06YNI0eOpGrVqvTu3ZuuXbsCzqJzgFatWtGpUyd++OEHrrzySs4880yio6M599xzSU1NZcCAAQDccMMN3HrrrVxzzTWsXbuWE044gQYNGnDqqacC0KNHD7KyfLu+S0RERHzP6zpQxpgxxpg2Bd/GAtm+bdKh/LUobdeuXWRkZFC1alXuuOMOateuXbRbrnr16iQlJZGTk8Mbb7zB5MmT+eeff9ixYwcpKSkkJiaSmJjIxo0bi17v/vvv59JLL2XIkCH88ssvrFq1il9//ZXKlSsXLQ6PiYnBGIMxhm+++Ya2bdty/vnnM3v2bGbPnk3r1q3L1ScREREJjLKMQD0HTDTGWOBLa61fK2T5a1HanDlz6NKlC0uXLmX06NHs3LmTESNGMGnSJP79738TGxvLrFmzqFSpEtdddx3gTMH16tWraATq3HPPBWDbtm088MAD1K9fnx9++IHffvuNO++8kxEjRlCrVi06duzIlClTaNCgAb179+byyy9nzpw5jB07lh49epCYmAhARkZ4FhsTEREJN8bacs2wlSohIcGmpaUd8tiyZcto2rSpX+/rD4UVyCtWPDJ37t+/v+hxay35+flFBTSttYevISuSm5tLdHT0Ue8bqv9eIiIiPpGTAzGBqSdljFlorU0o7Tod5eKFihUrFhueCv+ukDHmkOrjJYUnoNTwJCIiErE2boRHHoHTToMtW9xuzSFcO8rlaKMycoC/RwhFRESCzpYtkJICL70Ee/fCHXdAkJ1D60qAqlKlClu2bKFmzZoKUUdhrWXLli1F5/OJiIiEte3b4YUXYORI2LULunSBp5+GRo3cbtkRXAlQderUYd26dWzevNmN24eUKlWqUKdOHbebISIi4j+7dsGoUTBiBGzbBh07wjPPwJlnut2yErkSoKKjo4mPj3fj1iIiIhIscnJgzBhITobNm+Hqq2HQIGjRwu2Wlcq1NVAiIiLiudT0rPA5Z27vXnj9dRg6FP76Cy67DAYPhoIC1aFAAUpERCTIpaZn0Xf60qKzYbOyc+g7fSlAaIWo3Fx4+21nlGntWmjdGt55By6+2O2WeU1lDERERIJcyoyMovBUKCc3j5QZIVKAOS8PJk2Cpk2ha1c4+WT48kv49tuQDE+gACUiIhL01hdzJuzRHg8a+fnw/vvQrBnceitUqwYffQQ//OBM24XwTnxN4YmIiAS52rExZBUTlmrH+r86d5nWXlkLH38MAwbA4sXOyNP770NSElQIj7Gb8OiFiIhIGOvVvgkx0VGHPBYTHUWv9k38et/CtVdZ2TlYDqy9Sk3PKv4J1jpTcxdcANdd55QnmDQJli51ShOESXgCBSgREZGg16FFHMOTmhEXG4MB4mJjGJ7UzO8LyL1ae1W4nql9e9iwwdllt2wZ3HwzREUdeX2I0xSeiIhICOjQIi7gO+48Wnv1ww/Qvz989RWccgqMHg133w2VKweole7QCJSIiIgUq6Q1VrVjY2DRIqfw5YUXOuucXngBVqyABx8M+/AEClAiIiJSguLWXp297U/enzkCzjsP5s+HYcNg5Uro2RNi/L+oPVhoCk9ERESKVThlmDIjg8or/6DPj+9x2ZJZmGrVnEN+e/aE445zuZXuUIASERFxSSgcz9KhRi4dlk9yKohXrgy9e8Pjj0PNmm43zVUKUCIiIi4I+uNZ1q1zzqp74w2n/MBDD0GfPlCrltstCwpaAyUiIuKCoD2eZeNGZ2quYUMnPHXt6iwOHzlS4ekgGoESERFxQdAdz7JlC6SkwEsvwd69cPvtTnmCevXcaU+QU4ASERFxgZvHsxxi+3anBMHIkU7l8JtuchaIN24c2HaEGE3hiYiIuMCt41mK7NoFw4dDfDwMGgSXX+4cuTJ5ssKTBzQCJSIi4oKDSwQEdBdeTg6MGQPJybB5M1x1lROgzj3Xv/cNMwpQIiIiLgno8Sx79zrn0w0dCn/9Be3aweDBzsG/4jUFKBERkTByeG2pJ9rW57qlXzujTGvXwkUXwTvvOAf/SpkpQImIiISJg2tLVcjP4/x5n3HOc+/AtvVw/vnw2mtw2WVgjNtNDXkKUCIiImEiZUYGe/blcmXGfB79bjKNtvzJbyfF88Rtg3lu/FMKTj6kACUiIhIOrKVp2mxemzuJMzatIrPmqTx4XR8+b/JvMBV4TuHJpxSgREREQpm1MHMm9O/P6z/+yOrYU3jk6sf4qGkb8is4ZRLiAl1bKgIoQImIiISqOXOgXz+YOxfq1iV9QAq35Z7OzvwDo00BrS0VQVRIU0REJNT88IOzGPzii+GPP+Dll2H5cloMfJzBN7QgLjYGgzPyNDypWXAcThxmNAIlIiISKtLTYcAA+OQTOOEEeP55eOABiDkwRRfQ2lIRTAFKREQk2P36q3M+3bRpEBvrFMN8+GGoVs3tlkUsBSgREZFglZkJAwfClClOWOrfHx591AlR4ioFKBERkWCzerVzzMqECVCpEjzxBPTqBTVr+uwWh1csD8g5fGFEAUpERCRYZGXBsGFOxfAKFaB7d+jTB04+2ae3ObhiOUBWdg59py8FUIjykEe78IwxtYwxcwu+rmuMmW2MmWWMGWeMKnOJiIiUy6ZNztRcgwYwbhzcfbezu+7FF30ensCpWF4Yngrl5OaRMiPD5/cKV6WOQBljagATgKoFD90HPGCtXWaM+RxoBizxXxNFRETC1NatkJICo0bBnj1w223OLrv4eL/edn12jlePy5E8mcLLAzoDHwJYa5866O9qAn/7oV0iIiLha/t2Z3TphRdg50648UZnl12TwBS8rB0bQ1YxYam2KpZ7rNQpPGvtDmvt9sMfN8Z0Bn611q73S8tERERCVGp6Fq2SZxHf51NaJc8iNT3L+YvduyE52RlheuYZaNcOlixxdtkFKDwB9GrfhJjoqEMeU8Vy7xhrrWcXGjPbWptY8HV94P+AdiWEq3uBewHq1q173po1a3zWYBERkWB2+AJtgFj2MzE3nWaTxjjrna66CgYNgnPPdbWd2oV3JGPMQmttQqnXeRugCtZEfQF0tdYuLe15CQkJNi0tzaN7iIiIhLpWybOKpsei83LpvGQm3ee/y8m7tjojToMGwYUXutxKKYmnAaosZQz6AHWBlwo24D1trf22DK8jIiISdtZn5xCVn0fSL1/TY9671NmxiR/rnMEj1zzOu1P6ut088RGPA1Th9J21tjfQ218NEhERCVl5edyxah63zpxA/W3r+fmURvS9ojtz67UgrsYxbrdOfEiFNEVEpIjWxZRRfj588AEMGMDTv/3Gslr1ufv6/nzdoCUYowXaYcijQpoiIhL+Chc/Z2XnYDlQnbpoB5kcyVr45BM47zzo2NEJUu+9R8ans/k9IRFjDHGxMQxPaqYgGmY0AiUiIsDRq1Prw/8w1sJXXzmH+y5Y4FQQnzgRbroJoqLoAHQ471S3Wyl+pBEoEREBVJ3aY3PnQmIiXH45/PUXvP46LFsGt9wCUVGlPl3CgwKUiIgAJVehVnXqAgsWOKGpTRvIzISXX4bly51z66Kj3W6dBJgClIiIAKpOXaL0dLjmGrjgAufrESOcg367dYPKld1unbhEa6BERASgaJ2TduEV+O0353y6qVMhNhaGDoWHH4Zq1dxumQQBBSgRESnSoUVc5AamQpmZMHCgcz5dtWowYAD07OmEKJECClAiIiIAa9bA4MEwfjxUqgRPPAG9ekHNmm63TIKQApSIiES29eud6bnXXgNjoHt36NMHTj7Z7ZZJEFOAEhGRyLRpEyQnw5gxsH+/s5uuXz+oU6fEp6hSuxRSgBIRkciydauzk27UKMjJYc1VHXns9GtZWCGW2pOW06u9KTYUFVZqLyw2WlipHVCIikAqYyAiIpFhxw5ncXh8vDPydO21fDX1G65ofidpFWJLPb7maJXaJfIoQImISHjbvRuefdYJTs88A+3awZIlMGUKT2fs9zgUqVK7HEwBSkREwtJHP6zgf1d34++T6kCfPmw44xxIS4Np0+CsswDvQpEqtcvBFKBERCSkpKZn0Sp5FvF9PqVV8qwjp9v27ePnJ4fzr8v/RY9PXyHjxLok3ZLCJYm9SK1w6M46b0KRKrXLwRSgREQkZBQu5M7KzjlyzdL+/fDmm9C4MecMf5K1x9biphuHcfONw1gU17TYqTlvQlGHFnEMT2pGXGwMBoiLjWF4UjMtII9Q2oUnIiIho7iF3Hv37mNx8mg6pE91qognJHB7y7v4Nv5cp67TQQ6fmvP2+BpVapdCClAiIhIyDg5AxubTfvn3PDp3Mo23rIWzz4YPP4RrruGPZ78BD9cxKRRJWWgKT0REQkbt2BiwlrZ//Mgn4x9hbOpwKth8+t/UH9LT4dprwRitVxK/0wiUiIh4zZWK3Nby3HEbqfbyQJpnZbAm9mR6XvUoXzZvy9CO50CFA2MC3k7NiXjLWGv9eoOEhASblpbm13uIiEjgHF6RG5zRHb8uqJ4zB/r3hzlz+Ofk2oy68EbeaNCGk2pWVzASnzLGLLTWJpR2nUagRETEK0eryO3zILNggROcZs50Dvd96SWOuece+lSuTB/f3knEK1oDJSIiXglIRe6ff3bWM11wgbO2acQIWLECuneHypV9dx+RMlKAEhERr/i1Ivdvv8ENN0CLFjB3LgwZAitXwmOPwTHHlP/1RXxEAUpERLzilx1umZlwyy3OEStffOFM261aBU89BdWrl7PFIr6nNVAiIuIVn+5wW7MGBg+G8eOhUiVnpKl3bzjhBN82WsTHFKBERMRr5S4+uX49DB0Kr73mVAvv1g369nUWiouEAAUoEREJnE2bIDkZxoxxzq67+25nmu7UU91umYhXFKBERMT/tm51dtKNGgU5OXDrrTBgANSv73bLRMpEAUpERPxnxw4YORJeeMH5+sYb4emn4fTT3W6ZSLkoQImIiO/t3g0vvwzPPeeMPnXoAAMHOgf+ioQBBSgREfGdPXtg7FgYPtxZ73TllTBoECSUejKGSEhRHSgRESm/ffucheENG0LPnk49p3nz4LPPFJ4kLClAiYhI2e3fD2+9BU2awIMPwmmnwddfO3/+/W+3WyfiNwpQIiLivbw8mDIFzjgD7roLataEzz+H776Dtm3dbp2I33kUoIwxtYwxcw/6vqkx5kP/NUtERIKStTB9OjRvDjff7Bzs+8EH8NNPcMUVTlFMkQhQaoAyxtQAJgBVC75vAKQAx/m3aSIiEjSshU8/hfPOg+uvd6bu3n0XFi92dtgpOEmE8WQEKg/oDOwo+H4ncL3fWiQiIsHDWvjqK2c909VXQ3Y2TJgAv/wCnTtDBa0EkchU6v/zrbU7rLXbD/p+k7V2r3+bJSIirps7Fy65BC67DNatg3HjICMDbrsNKqoKjkQ2v/yngzHmXmNMmjEmbfPmzf64hYiI+EvheqY2bZzANGoUZGbCPfdAdLTbrRMJCn4JUNbacdbaBGttwoknnuiPW4iIiK8tXgzXXQctW8LChZCSAitWwEMPQZUqbrdOJKhoDFZEJNItW+acT/f++xAbC4MHQ48eUL16wJqQmp5FyowM1mfnUDs2hl7tm9ChRVzA7i/iLY8DlLU28Wjfi4hIiFmxwjmfbvJkOOYY6N8fHn3UCVEBlJqeRd/pS8nJzQMgKzuHvtOXAihESdDS9gkRkUizdq2znqlJE5g6FR57DFatcs6sC3B4AkiZkVEUngrl5OaRMiMj4G0R8ZSm8EREIsX69TBsGLz2mvN9t27Qty+cfLK7zcrO8epxkWCgACUiEu42b4Znn4XRo50CmHfdBf36wamnut0yAGrHxpBVTFiqHRvjQmtEPKMpPBGRcLVtGzz1FMTHw8iR0KmTU5bg1VeDJjwB9GrfhJjoqEMei4mOolf7Ji61SKR0GoESEQmAgO4y27EDXnwRXngBtm+HG290dtmdfrp/7ldOhf8O2oUnoUQBSkTEzwK2y2z3bmea7tlnYetW+O9/nV12zZr57h5+0qFFnAKThBQFKBERPzvaLjOfhIY9e5xpueHDYeNGuPJKZ0ddQgKgGksi/qAAJSLiZ37bZbZvH7z1llP4MisL2raF6dOdg38LqMaSiH9oEbmIiJ+VtJuszLvM9u+H8eOdOk733w+nnQazZsHXXx8SnkA1lkT8RQFKRMTPfLbLLD8f3nkHzjwT7rwTataEzz+H776DSy4p9imqsSTiHwpQIiJ+1qFFHMOTmhEXG4MB4mJjGJ7UzPMpNGvhgw+geXPo0gUqV4bUVPjpJ7jiCjCmxKf6fPRLRACtgRIRCYgy7TKz1hlh6t8fFi1ypuzefRduuAEqePbfv73aNzlkDRSoxpKIL2gESkQkGM2aBa1awVVXOQUxJ0yAX36Bzp09Dk/gg9EvESmWRqBERILJvHnOMSuzZ0OdOjBuHNxxB0RHl/kl3ayxpBIKEq4UoEREgkFamjNV98UXUKsWjBoF99wDVaqU+JRgDycqoSDhTAFKRAIu2D/4A2rJEhgwAD780NlVl5ICDz4Ixxxz1KeFQjjxewFRERdpDZSIBFThB39Wdg6WAx/8qelZbjctsH7/3TmjrnlzZ7pu8GBYtQoef7zU8AShUd9JJRQknGkESkQCKuJHJVascI5ZmTTJCUr9+sGjj0KNGkWXeDJCFwrhpHZsDFnFtEclFCQcaARKRAIqFD74/WLtWrj3Xjj9dHj/fXjsMWfEafDgI8KTJyN0oVDfyWcFREWCkAKUiARUKHzw+9Rff8FDD0GjRk4pgvvvd0ahnnsOTjjhiMs9nZoLhXCiEgoSzjSFJyIBFTGFHTdvdkLSyy87Z9fddRc89RTUrXvUp3k6QlcYQoJ9Mb6bJRRE/EkBSkQCKlQ++Mts2zZ4/nl48UXIyYFbbnF22TVo4NHTvVk3pHAi4h4FKBEJuLD84N+xA/73Pyc8bd/uVAx/5hlnzZMXImaETiTEKUCJiJTH7t0werQzXbdlC1x3nbPL7uyzy/RyYT9CJxImFKBERMpizx549VUYPhw2boQrrnCC0/nnl/ulw3KETiTMKECJiHhj3z546y2n/EBWFiQmwrRpzsG/IhIxVMZARMQT+/fD+PHOmqb773d20339NXzzjcKTSARSgBIROZr8fHjnHTjzTLjzTqfo5Wefwbx50Lat260TEZcoQImIFMda+OAPA62pAAAd30lEQVQD56y6Ll2gUiXn+7Q0uPJKMMbtFoqIixSgREQOZq0zwnT++ZCU5Kx5eucdWLwYOnRQcBIRQAFKROSAWbOc9UxXXQVbtzqLxX/9FW68ESro16WIHKDfCCIi330Hl1wCl14Kf/4JY8fC77/DHXdARW1WFpEjKUCJSOT66SenflPr1rBsmVNJPDMT7rvPWfMkIlICBSgRiTxLljjrmVq2dBaFP/ccrFgBDz8MVaq43ToRCQEamxaRyLFsmXM+3XvvwbHHOpXDe/RwvhYR8YIClIiEvxUrYOBAmDwZYmLgySfh8cedmk4iImWgACUiR5WanhW6B9uuXQtDhsCbb0J0NPTsCb17w4knut0yEQlxHgUoY0wtYKq1trUxJhqYDhwPvGGtfdOfDRQR96SmZ9F3+lJycvMAyMrOoe/0pQDBHaL++guGDYNx45y6Tg884Iw6nXKKxy8R0sFRRPyu1EXkxpgawASgasFDDwELrbWtgI7GmOp+bJ+IuChlRkZReCqUk5tHyowMl1pUis2boVcvqF8fxoyB22+HP/6Al17yOjz1nb6UrOwcLAeCY2p6lv/aLiIhxZNdeHlAZ2BHwfeJwHsFX88BEnzfLBEJBuuzc7x63DXbtkG/fhAfDy+8ADfc4NRxGjfOOfTXSyEXHEUk4EqdwrPW7gAwB44vqAoU/mfYVqDW4c8xxtwL3AtQtwy/vEQkONSOjSGrmLBUOzbGhdYUY8cOp3bT88/D9u1OcBo4EJo2LdfLhkxwFBHXlKUO1C6g8LdnteJew1o7zlqbYK1NOFGLNUXKLTU9i1bJs4jv8ymtkmcFbCqpV/smxERHHfJYTHQUvdo3Ccj9S/TPP5CS4kzVDRgAF18MP//slCcoZ3iCkgNi0ARHEXFdWQLUQuCigq+bA6t91hoROYKb63E6tIhjeFIz4mJjMEBcbAzDk5q5t5h6zx4YNcoJTk88AQkJsGABfPghNG/us9t4ExzdCrci4q6ylDGYAHxmjGkNnAEs8G2TRORgR1uPE4gg06FFnPu7z3JznYN9Bw+GdeucEaepU+Gii0p/bhkU9re0XXghu0tRRMrN4wBlrU0s+N81xpjLcEahBlhr8476RBEpl4hej7N/v1P8cuBAWLUKLrwQxo+Htm3hwLpMv/AkOLodbkXEPWUqpGmtXc+BnXgi4kdBv5C7gE/rJuXnO+uZnnkGMjLg3HPh5Zfhyiv9Hpy8EdHhViTC6TBhkSAXtAu5D+KzdVrWQmoqnHMO3HSTUz18+nTnwN///CeowhNosblIJFOAEglyQbeQuxjlrptkLXz+OZx/Pvz3v7B3L7zzDixe7HwfZMGpUCiEWxHxD52FJxICgmIh91GUayrrm2+cIpjz50O9es4ap5tvhorB/+vJ08XmIhJ+gv83lIgEvTKt05o/3wlO33wDcXEwdizceSdUquTHlvpesIdbEfEPTeGJSLl5NZWVluYsBm/VCn77zakk/scfcN99IReeRCRyaQRKRMrNo6mspUudquGpqXD88ZCcDN27Q9WqJbyqiEjwUoASEZ8ocSrr99+dcgTvvQfVq8OgQdCjBxx7bMDbKCLiKwpQIuIfK1c6YWniRIiJgSefhMcegxo13G6ZiEi5KUCJiG/9+ScMGQJvvunspOvZE3r3Bh0sLiJhRAFKRHzjr79g+HB49VWnrtP990PfvlC7ttstExHxOQUoESmfv/+G555zjlrZt88pRdCvH5x2mtstExHxGwUoESmb7Gx4/nl48UXYvRtuucXZZdewodstExHxOwUoEfHOzp1O7abnn3dCVKdOzi67pk3dbpmISMAoQIlEqNT0LO+OIPnnH3jlFad+05YtcO21zi675s2Dp40uvaaIRB4FKJEIlJqeRd/pS4sOAM7KzqHv9KUAR4aJvXth3DgYNgw2bID27Z3g1LJl8LTRxdcUkciko1xEXJSankWr5FnE9/mUVsmzSE3PCsh9U2ZkFIWIQjm5eaTMyDjwQG4uvPYaNGoEDz8MTZrAnDnwxRd+D08etzEIXlNEIpNGoERc4uZoyPpiDv4tejwvDyZPhoEDnWKYF1wAb70FbduCMX5tl8dtDKLXFJHIpBEoEZe4ORpSOzbmiMeMzefWtT/AWWfB7bfDccfBJ5/A/Plw6aUBDU8ltfFoj7v1miISmRSgRFzi5mhIr/ZNiImOcr6xlssyf+Dz8T0Y9M4QiIqCadNg4UK46qqAB6di21ggJjqKXu2bBNVrikhk0hSeiEtqx8aQVUxYCsRoSIcWcWAtc16axO1fvEnzDZnsqhsPU6Y4ZQmiokp/kUC0EXy6Y84frykikclYa/16g4SEBJuWlubXe4iEosPXQIEzGjI8qZn/P9Bnz3aqhc+bB/XqOQUwb73VObsuBKk0gYj4ijFmobU2obTrQvO3pUgYcGU0ZP586N8fZs2CuDgYMwbuugsqVfLfPf1MpQlExA0KUCIu6tAiLjAf8gsXOsHp88/hpJOc41fuuw+qVPH/vf3saIvxFaBExF+0iFwknC1dCklJkJAACxY4VcRXroQePcIiPIFKE4iIOxSgRMJRRgbcdJNzzMrXXzs1nVatgt69oWpVt1vnUypNICJuUIASCScrV8Idd8AZZ8DHH0Pfvk5wGjAAjj3W7db5hUoTiIgbtAZKxENBvdPrzz9hyBB4801nJ12PHtCnj7PeKcypNIGIuEEBSsQDQbvTa8MGGD4cxo4Fa52F4U8+CbVru9cmFwRsMb6ISAFN4Yl4IOgOof37b3jiCahfH0aPdmo4ZWbCyy9HXHgSEXGDRqBEPBA0O72ys+H5550yBLt3w803w9NPQ8OGgW2HiEiEU4AS8YCbx64AsHMnjBoFI0Y4IeqGG+CZZ5zF4iIiEnCawhPxgGs7vf75xwlN9es7R69cdBGkp8N77yk8iYi4SCNQIh4I+E6vvXth3DgYNsxZKH755TBoEPzrX/65n4iIeEUBSsRDAdnplZsL48fD4MFOaYI2bZzRptat/XtfERHxiqbwRIJBXh68/Tacfjrce6+zk27mTJg9W+FJRCQIeR2gjDHxxphPjTFzjTHP+6NRIhEjP98ZYTrrLLj9dqda+Mcfw/ffQ7t2YIzbLRQRkWKUZQTqWWCwtbY1UMcYk+jbJolEAGvhww+hRQvo3BkqVICpU2HhQrj6agUnEZEgV5YA1RhYVPD1JuA43zVHJMxZC198AS1bQocOzi67SZNgyRK4/nonSImISNAry2/rqcDTxphrgCuArw+/wBhzrzEmzRiTtnnz5vK2USQ8FK5nuvJK2LwZ3ngDli1zimFGRZX6dBERCR5eByhr7RDgc6ArMMFau6uYa8ZZaxOstQknnniiD5opEsK+/x4uvRQuuQRWrYJXXoHly+Guu5yDf0VEJOSU9bf3z0Bd4CYftkUkvCxaBP37w2efwUknwciRzmG/MQGqXi4iIn5T1gDVC3jBWvuPLxsjEhaWLnXOp/vgA6hRA5KToXt3qFrV7ZaJiIiPlGnFqrX2aWvtRF83RiSkLV8OXbpA8+bkzvyK1y+9nbNvH0srez6py7Pdbp2IiPiQFmCIlNeqVc4xK2+/DTExZNzRjduPb8OGiscAsCM7h77TlwL4v5K5iIgEhPZMi5TVunVw//3QuDG8+y488gisXMldjf9bFJ4K5eTmkTIjw6WGioiIr2kESsRbGzY465rGjnUqid93Hzz5pHP8CrA+O6fYp5X0uIiIhB4FKBFPbdkCzz0HL78Me/fCnXdCv35w2mmHXFY7NoasYsJS7VjtvhMRCReawpOQkpqeRavkWcT3+ZRWybNITc/y/02zs2HAAIiPh5QUSEqC33+H1147IjwB9GrfhJjoQwtjxkRH0at9E/+3VUREAkIjUBIyUtOz6Dt9KTm5eQBk+Xtx9q5dMGqUE5qys+GGG+CZZ+CMM476tMK2pMzIYH12DrVjY+jVvokWkIuIhBEFKAkZKTMyisJTocLF2T4NJzk5TrXw5GT4+2+45hpnl90553j8Eh1axCkwiYiEMU3hScjw++LsvXth9Gho0AAefxzOPRcWLICPPvIqPImISPhTgJKQUdIi7HIvzs7Nhddfd8oRdO8OjRrBnDkwYwa0bFm+1xYRkbCkACUhw+eLs/PyYOJEaNoU7rkHTjkFZs6E2bOhdevyN1hERMKW1kBJyPDZ4uz8fJg2zTmvbtkyaNECPvkE/vMfMMYPLRcRkXCjACUhpVyLs62Fjz92ShIsXuzspps2jdTTzidlZibr534W8jvmUtOztPtPRCQAFKAiQMR/qFoLX34J/fvDTz9Bw4YweTJ07kzqkg2BLY3gRwEv8yAiEsG0BirMFX6oZmXnYDnwoRqQApTB4NtvoU0buOIK2LQJ3nzTmbbr0gWioo5aGiHUhFNfRESCnQJUmIvYD9UffoDLLoPERFi50qnrtHy5c/xKxQMDr+F0bl049UVEJNgpQIW5iPtQXbQIrr4aLrwQliyBF16AP/6ABx6ASpWOuNxvpRFcEE59EREJdgpQYS5iPlR/+QWuvx7OOw/mz4fhw2HFCujZE2JK7ms4nVsXTn0REQl2ClBhLuw/VJcvh5tvhrPPhq++cs6qW7UK+vSBatVKfXqHFnEMT2pGXGwMBoiLjWF4UrOQXHQdTn0REQl2xlrr1xskJCTYtLQ0v95Dji4sd+GtXu2cT/f221C5MvTo4Ry/cvzxbrdMRERCmDFmobU2obTrVMYgAoTVwbZZWTB0qHP0SoUK8PDDzmjTSSe53TIREYkgClASGjZuhORkGDPGqSTetSs89RTEhUkwFBGRkKIAJV4L6JTgli2QkgIvvQR798Idd0C/flCvnn/uJyIi4gEFKPFKwKpdb9/ulCAYORJ27XIKXz79NDRq5Lt7iIiIlJF24YlX/F6Yc9cuGDYM4uOdReLt28PSpTBpksKTiIgEDY1AiVf8VpgzJ8dZ35ScDJs3O8UwBw2CFi3K97oiIiJ+oBEo8YrPC3Pu3QujR0ODBvDYY9C8uXMMy8cfKzyJiEjQUoASr/isMGdurlOKoHFj6N4dGjaE2bNh5kz4179812ARERE/0BSeeKVwoXiZd+Hl5cGUKTBwoHPUSsuWTpBq1w6M8WPLRUREfEcBSrxWpsKc+fkwdapz1MqyZc5U3ccfw1VXKTiJiEjI0RSe+Je18NFHznqmzp2dx95/HxYtchaKKzyJiEgI0giU+Ie18OWX0L8//PSTs8Zp0iS48UaIijri8rA8r09ERMKWRqDE9779Ftq0gSuucI5gef11+O03uPnmEsNT3+lLycrOwXKgOGdqelbg2y4iIuIBBSjxne+/dxaDJyY6C8RHj4bly+HuuyE6usSn+b04p4iIiI8pQEn5Fa5n+ve/YckS5wiWFSvgwQehcuVSn+634pwiIiJ+ogAlZffLL3D99XDeeTB/vnMEy8qV0LMnxHheWNPnxTlFRET8TAFKvLd8uXO479lnO4Uvn34aVq2Cvn2hWjWvX85nxTlFREQCxOtdeMaYGsBk4CRgobX2Pp+3SoLT6tXO+XQTJkCVKvDEE9CrF9SsWa6XLXdxThERkQArSxmDW4HJ1trJxpgpxpgEa22arxsmQWTdOhg6FN54AypUgIcfhj59oFYtn92iTMU5RUREXFKWALUFOMsYEwucCvzp2yZJ0Ni4EYYPh7FjnUriXbvCk09CnTput0xERMRVZQlQ3wFXAQ8Dy4Cth19gjLkXuBegbt265WmfuGHLFkhJgZdegj174PbbnYKY8fFut0xERCQoGGutd08w5k3gEWvtDmPMo8Aua+24kq5PSEiwaWma4fOUqxW5t293ShCMHAm7dsFNNzkLxBs3Dsz9RUREXGaMWWitTSjturLswqsBNDPGRAH/ArxLYFIi1ypy79oFw4axr+5pMGgQn5/SjFsefo3Ux59TeBIRESlGWabwhgNvAacB3wPv+LRFEexoFbn9MgqVkwNjxkByMmzezPyGLUn5bxd+PbkhAAunLwXQ4m4REZHDeB2grLU/Amf6oS0RL2AVuffudc6nGzoU/voL2rXj3obX8uVx9Q+5zK/hTUREJISpkGYQ8XtF7txcpxRB48bQvTs0aADffAMzZzLzsPBUSMepiIiIHEkBKoj4rSJ3Xh5MmgRnnOGUIqhVC2bMgDlznIN/0XEqIiIi3lCACiIdWsQxPKkZcbExGCAuNobhSc3KPoWWnw9Tp0KzZnDrrXDMMfDhh7BgAVx+ORhTdKmOUxEREfFcWRaRix/5pCK3tfDJJ07tpsWL4fTT4b33nIN/KxSfmcPxOBVXS0KIiEhYU4AKJ9Y6h/v27w8//uiscZo40annFBVV6tPD6TiVwpIQhbsaC0tCgHYViohI+WkKL1zMmQMXXwzt28OGDc4uu2XL4JZbPApP4eZoJSFERETKSwEq1BWuZ7r4YvjjD3j5ZVi+HO6+G6Kj3W6dawJWEkJERCKSAlSoSk+Ha66BCy6An3+G55+HFSugWzeoXNnt1rlOuwpFRMSfFKBCza+/QseOcO65MG+eUwxz5Up49FGIUTgopF2FIiLiT1pEHioyM2HgQJgyBapVcw757dkTjjvO7ZYFpXDcVSgiIsFDASrYrV4NgwfDhAnO1NwTT0CvXlCzptstC3rhtKtQRESCiwJUsMrKcqbnXn/dqd300EPQp49TRVxERERcpQAVbDZtguRkeOUV5wiWe+6BJ5+EOnXcbpmIiIgUUIAqhisVrLduhZQUGDUK9uyB226DAQMgPt6/9xURERGvKUAdJuAVrLdvh5EjnT87dzpVw59+Gho39v29RERExCfCIkD5csToaBWsfRqgdu+Gl16C556DbdsgKcnZZXfWWb67h4iIiPhFyAcoX48Y+b2CdU4OjB3rrHPatAmuugoGDXLqOomIiEhICPlCmr4+88xvFaz37YMxY6BhQ6fo5dlnw/z58MknCk8iIiIhJuQDlK9HjHxewXr/fnjzTWdN04MPOovCv/kGZs6ECy8s22uKiIiIq0I+QPl6xKhDiziGJzUjLjYGA8TFxjA8qZn304F5eTB5MpxxhnOw70knwRdfwNy5kJhYpraJiIhIcAj5NVC92jc5ZA0UlP/Ms3JVsM7Phw8+cEoQ/PYbNG8OH35Iap1zSflyOeu/+UzHioiIiIS4kB+B8tmIUXlZ66xnOu8857Df/Hx47z1YtIjUU8+j7we/kJWdg+XAQvfU9KzAtlFERER8IuRHoMDlM8+sha+/hn79YMECaNAA3n4bunSBKGctVcBKI4iIiEhAhPwIlKvmzHHWM112GaxfD6+9BsuWwa23FoUnCEBpBBEREQkoBaiyWLAALr8cLr4Yli93CmJmZkLXrhAdfcTlfiuNICIiIq5QgPJGejpccw1ccIHz9YgRsGIFdO8OlSuX+DSfl0YQERERV4XFGii/++0353y6qVMhNhaGDoWHHoLq1T16euE6p4AfUCwiIiJ+oQB1NJmZzvl0U6ZAtWpOaYKePZ0Q5SV/LHT35RmAIiIi4jkFqOKsXg2DB8OECVCpEjzxBPTqBTVrut2yIr4+A1BEREQ8pzVQB8vKgm7dnGNXJk921jatXOkc/BtE4Ql8fwagiIiIeE4jUACbNjkh6ZVXnCNYunaFp56COnXcblmJVBpBRETEPZEdoLZuhZQUGDUK9uyB225z1jnFx7vdslLVjo0hq5iwpNIIIiIi/heZU3jbtzuLw+Pj4dln4brrnJ12b70VEuEJVBpBRETETZE1ArV7t1P0MiXFGX1KSnKC1Flnud0yr6k0goiIiHsiI0Dl5MDYsc46p02b4D//gUGDnIN/Q5irZwCKiIhEsPCewtu3D8aMgYYN4dFHoVkzmD8fPv005MOTiIiIuKdMI1DGmAeAzgXfxgILrLX3+axV5bV/P7z9tjPKtGYNtGoFkybBJZe43TIREREJA2UagbLWjrHWJlprE4G5wGs+bVVZ5eU59ZvOOAPuvhtOPBG++ALmzlV4EhEREZ8p1xSeMSYOqGWtTfNRe8omPx+mTYOzz4ZbboGYGEhNhR9/hPbtwRhXmyciIiLhpbyLyLsBYw5/0BhzL3AvQN26dct5Cw/s2gX33AMnnQT/93/QsSNUCO/lXSIiIuIeY60t2xONqQDMA/5tj/IiCQkJNi0tAANUv/4KTZpAxcBuLNSBviIiIuHDGLPQWptQ2nXlSRutcRaPly2B+dqZZwb8ljrQV0REJDKVZ56rPTDHVw0JRTrQV0REJDKVeQTKWvukLxsSinSgr4iISGTSSutyKOngXh3oKyIiEt4iKkClpmfRKnkW8X0+pVXyLFLTs8r1ejrQV0REJDJFxll4+GfBtw70FRERiUwRE6COtuC7PIFHB/qKiIhEnoiZwtOCbxEREfGViAlQWvAtIiIivhIxAUoLvkVERMRXImYNlBZ8i4iIiK9ETIACLfgWERER34ioACWBp8OWRUQkHClAid/osGUREQlXEbOIXAJPhy2LiEi4UoASv1HtLRERCVcKUOI3qr0lIiLhSgFK/Ea1t0REJFxpEbn4jWpviYhIuFKAEr9S7S0REQlHmsITERER8ZIClIiIiIiXFKBEREREvKQAJSIiIuIlBSgRERERLylAiYiIiHhJAUpERETESwpQIiIiIl5SgBIRERHxkgKUiIiIiJeMtda/NzBmM7DGrzc54ATg7wDdK9io75FJfY9M6ntkUt8D4zRr7YmlXeT3ABVIxpg0a22C2+1wg/quvkca9V19jzTqe3D1XVN4IiIiIl5SgBIRERHxUrgFqHFuN8BF6ntkUt8jk/oemdT3IBJWa6BEREREAiHcRqBERERE/C7kApQxppYxZm4p10QbYz42xswzxtxV0mOhxhjzhjHme2NMv6Nc84AxZnbBn5+NMa8aYyoaY9Ye9HizQLbbFzzse7H9NMYMNMb8ZIwZHbgW+46HfT/OGPO5MeZLY8wHxphKofy+e9jnI67x5HnBrrQ+hNt7fTgP+h+WP+fgUd/D8vc7lP7ZHoyf6yEVoIwxNYAJQNVSLn0IWGitbQV0NMZUL+GxkGGMSQKirLUXAvWNMY2Ku85aO8Zam2itTQTmAq8BZwPvFD5urV0asIb7gKd9p5h+GmPOAy4CWgKbjDHtAtRsn/Ci7zcDL1hrLwc2AFcQou+7J30u7hov/q2Clod9CJv3+nAe9j/sfs7Bs76H4+938PizPeg+10MqQAF5QGdgRynXJQLvFXw9B0go4bFQksiB9n+J88uiRMaYOKCWtTYNuAC42hjzY8F/4VT0a0t9LxHP+l5cPy8Gpllnsd8MoLW/G+tjiXjQd2vtK9bamQXfnghsInTf90RK73Nx13jyvGCXSCl9CLP3+nCJlP4ehuPPOXjx/98w+/0Onn22JxJkn+tBHaAKhicLhyVnA49Ya7d78NSqQFbB11uBWiU8FrSK6ftDeNf+bsCYgq9/AtpZa1sC0cB//NBknylH34vrZ0S978aYC4Ea1tofCLH3/SCevGch/zNeAo/7ECbv9eE86X/I/5yXwJs+hOzv9+JYa3d48NkedD/zQZ1UrbX3lfGpu4AYYDtQreD74h4LWof33RjzP5z2g9P+EsOvMaYCcAnwVMFDS6y1ewu+TgOCemqjHH0vrp+F73tpzw0K5XzfjwdeAq4veCik3veDePKeFXdNSL3XJfCoD2H0Xh/Ok/6H/M95CTx970P693s5BN3neij+n8wTCzkw/NkcWF3CY6HEm/a3BhbYAzUqJhpjmhtjooAOwGK/tdI/PO17cf2MiPfdGFMJeB/oa60tPHsyVN93T/ocjj/j4EEfwuy9Ppwn72E4/pyD530It9/vngq+n3lrbcj9AWYf9HVboPthf38a8CvwP5zhzajiHnO7H172+VicH4wXgGXAccAZwJBirh0GJB30/VnAEmApMNTtvvir78X1E+c/EuYVvO8ZQLzb/fFT3x8AtgGzC/50DtX3vZg+Ny+mv8X9uxzxmNt98VPfw+a9LmP/w+7n3NO+F1wXVr/fD+vb7IL/DYnP9bAtpGmMqY2TTGfYgrnV4h4LJQU7FS4D5lhrN7jdnkAqT9+NMTHAVcAia+1Kf7TPnyLxffekz8VdEw7/VuHQh/Ioa/9D/ecc9N6XJtg+18M2QImIiIj4S7iugRIRERHxGwUoERERES8pQImIiIh4SQFKRERExEsKUCIiIiJeUoASERER8dL/AyjKJVG5GDVIAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "y_hat = sess.run(y_hat, {x: x_train, y: y_train})    # 模型的预测输出\n",
    "plt.scatter(x_train, y_train, label='原始数据')\n",
    "plt.plot(x_train, y_hat, c='r', label='拟合直线')\n",
    "# 显示图例\n",
    "plt.legend() \n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 关闭会话& 图复位"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "sess.close()    # 关闭会话 Session\n",
    "tf.reset_default_graph()    # 图复位"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TensorBoard"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建日志存放目录"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import  datetime\n",
    "\n",
    "now = datetime.utcnow().strftime('%Y%m%d%H%M%S')\n",
    "root_logdir = 'tf_logs'\n",
    "logdir = '{}/ch03/run-{}'.format(root_logdir, now)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构建计算图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = tf.placeholder(tf.float32, name='x')\n",
    "y = tf.placeholder(tf.float32, name='y')\n",
    "w1 = tf.Variable(tf.random_normal([1]), name='w1')\n",
    "w0 = tf.Variable(tf.zeros([1]), name='w0')\n",
    "y_hat = w0 + w1 * x\n",
    "loss = tf.reduce_mean(tf.square(y_hat - y))\n",
    "optimizer = tf.train.GradientDescentOptimizer(0.01)    # 学习率设为 0.01\n",
    "train = optimizer.minimize(loss)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 设置 TensorBoard"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 给损失模型的输出添加scalar，用来观察loss的收敛曲线\n",
    "loss_summary = tf.summary.scalar('loss', loss)\n",
    "# 模型运行产生的所有数据保存到文件夹供 TensorBoard 使用\n",
    "file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 会话 Session"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Iteration[20/500], loss: 49.139008\n",
      "Iteration[40/500], loss: 23.541363\n",
      "Iteration[60/500], loss: 11.763593\n",
      "Iteration[80/500], loss: 6.235038\n",
      "Iteration[100/500], loss: 3.559620\n",
      "Iteration[120/500], loss: 2.207230\n",
      "Iteration[140/500], loss: 1.483401\n",
      "Iteration[160/500], loss: 1.069147\n",
      "Iteration[180/500], loss: 0.815151\n",
      "Iteration[200/500], loss: 0.649443\n",
      "Iteration[220/500], loss: 0.535848\n",
      "Iteration[240/500], loss: 0.455141\n",
      "Iteration[260/500], loss: 0.396404\n",
      "Iteration[280/500], loss: 0.352993\n",
      "Iteration[300/500], loss: 0.320601\n",
      "Iteration[320/500], loss: 0.296292\n",
      "Iteration[340/500], loss: 0.277985\n",
      "Iteration[360/500], loss: 0.264170\n",
      "Iteration[380/500], loss: 0.253731\n",
      "Iteration[400/500], loss: 0.245839\n",
      "Iteration[420/500], loss: 0.239868\n",
      "Iteration[440/500], loss: 0.235351\n",
      "Iteration[460/500], loss: 0.231933\n",
      "Iteration[480/500], loss: 0.229345\n",
      "Iteration[500/500], loss: 0.227387\n"
     ]
    }
   ],
   "source": [
    "init = tf.global_variables_initializer()\n",
    "sess = tf.Session()\n",
    "sess.run(init)\n",
    "\n",
    "num_iter = 500\n",
    "for i in range(num_iter):\n",
    "    # 训练时传入loss_summary\n",
    "    summary, _ = sess.run([loss_summary, train], {x: x_train, y: y_train})\n",
    "    # 收集每次训练产生的数据\n",
    "    file_writer.add_summary(summary, i)\n",
    "    if (i+1) % 20 == 0:\n",
    "        print('Iteration[{}/{}], loss: {:.6f}'.format(i+1,num_iter,sess.run(loss,{x:x_train,y:y_train})))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
